#!/bin/sh
#
# This program automates the encrypt / decrypt this with openssl's AES-128-CBC
# implementation.
#
# This is important because some people want to ban or outlaw encryption "apps"
# like instant messengers. But what about raw, byte-by-byte encryption? Or 
# when we paste innocent-looking text in an online form?
# Encryption will ALWAYS prevail!
#
# Copyright 2022 - kzimmermann. All rights reserved.
#
# This program is Free Software licensed under the terms and conditions of the
# GNU GPL v3.0. See https://www.gnu.org/licenses for more information.
#
# Instructions:
# 
#  At first run, this program creates $HOME/.config/sessioncrypt.conf which 
#  contains a random symmetric key. You can substitute the value there for your
#  own, but MAKE SURE IT IS ACTUALLY RANDOM!
#  Standard operation is to encrypt a plaintext using said key. Pass '-d' to 
#  make it decrypt instead.
#

set -euo pipefail

conf_file="$HOME/.config/sessioncrypt.conf"

is_pipe=0

# Test to see if you're receiving piped data. Thanks, SO.
if [ -t 0 ]
then
    is_pipe=0
else
    is_pipe=1
fi

init() {
    # No parameters used.
    # Performs initiation sequences for Sessioncrypt program.
    # Will "reboot" configs if they already exist, so be careful.  
    # Returns: nothing.
    echo "Creating config file at $conf_file"

    # Note the clobber right here ----------------v
    echo "# Configuration file for sessioncrypt." > "$conf_file"
    echo "# Lines beginning with a '#' are ignored." >> "$conf_file"
    echo "Generating random symmetric key..."
    rand_key=$(head -c30 /dev/urandom | base64)
    echo "KEY=$rand_key" >> "$conf_file"
    echo "Applying restrictive permissions to config file."
    
    # Yeah yeah, not really perfect, but obfuscating this would require gpg
    chmod 600 "$conf_file"
}

encrypt() 
{
    # $1 - plaintext to be converted
    # $2 - secret key
    # Returns: string IV:ciphertext, where IV is base64-encoded.
    IV=$(openssl rand 16 | xxd -ps)
    #CT=$(echo "$1" openssl enc -salt -aes-128-cbc -pbkdf2 -iv "$IV" -in "$1" -pass pass:"$2" -a |
    CT=$(echo "$1" | openssl enc -salt -aes-128-cbc -pbkdf2 -iv "$IV" -pass pass:"$2" -a |
        tr -d "\n")
    echo "$(printf "$IV" | base64):$CT"
}

decrypt() 
{
    # $1 - ciphertext to be decrypted, including IV.
    # $2 - secret key
    # Returns: string of plaintext
    IV=$(echo "$1" | cut -d ":" -f 1 | base64 -d) || { 
        echo "Error: IV value not found!"
        exit 1
    }
    CT=$(echo "$1" | cut -d ":" -f 2)
    echo "$CT" | openssl enc -d -salt  -aes-128-cbc -pbkdf2 -iv "$IV" -pass pass:"$2" -a
}

# Tester function. To make sure both functions are working correctly.
dryrun() {
    input="roquefort cheese is delicious"
    echo "To encrypt: '$input'"
    printf "Password: "
    read -s key
    echo ""
    ciph=$(encrypt "$input" "$key")
    echo "---------"
    echo "Ciphertext: $ciph"
    printf "Plaintext: "
    decrypt "$ciph" "$key"
}

main() 
{
    if [ ! -f "$conf_file" ]
    then
        echo "Preparing for first run..."
        init
    fi

    # Parse key from config
    key=$(cat "$conf_file" | awk -F= '/KEY/ {print $2}')
    
    if [ "$#" -eq 0 ]
    then
        if [ $is_pipe -eq 1 ]
        then
            read -r plain
        else
            printf "Enter a text to encrypt: "
            read plain
            echo
        fi
        encrypt "$plain" "$key"
        exit 0
    fi

    if [ "$1" = "-i" ]
    then
        printf "Delete current configs (including key) and create new ones? (y/n) "
        read decision
        echo " "
        if [ "$decision" = "y" ]
        then
            init
            echo "Configurations re-created. Restart the program to use."
            exit 0
        else
            exit 0
        fi
    fi

    if [ "$1" = "-d" ]
    then
        if [ $is_pipe -eq 1 ]
        then
            read -r cipher
        else
            printf "Enter text for decryption: "
            read cipher
            echo
        fi
        decrypt "$cipher" "$key"

    elif [ "$1" = "-D" ]
    then
        dryrun
        exit 0

    elif [ "$1" = "-h" ]
    then
        echo "Usage: $(basename $0) [-d] [-D] [-h]"
        echo "Encrypts a message with AES-128-CBC"
        echo "Where:"
        echo " -d : decrypts text instead of encrypting"
        echo " -i : regen config (and keys)."
        echo " -D : dry-run (test)"
        echo " -h : this help text."
        exit 0
    else
        echo "Unknown option. Try -h"
        exit 1
    fi
}

main $*
